package com.jdk.demo.nio.bilibili.Maodun.net.qiujuer.library.clink.impl.async;

import java.io.IOException;
import java.util.concurrent.atomic.AtomicBoolean;

import com.jdk.demo.nio.bilibili.Maodun.net.qiujuer.library.clink.box.StringReceivePacket;
import com.jdk.demo.nio.bilibili.Maodun.net.qiujuer.library.clink.core.IoArgs;
import com.jdk.demo.nio.bilibili.Maodun.net.qiujuer.library.clink.core.ReceiveDispatcher;
import com.jdk.demo.nio.bilibili.Maodun.net.qiujuer.library.clink.core.ReceivePacket;
import com.jdk.demo.nio.bilibili.Maodun.net.qiujuer.library.clink.core.Receiver;
import com.jdk.demo.nio.bilibili.Maodun.net.qiujuer.library.clink.utils.CloseUtils;

public class AsyncReceiveDispatcher implements ReceiveDispatcher {

	private final AtomicBoolean isClosed =  new AtomicBoolean(false);
	private final Receiver receiver;
	private final ReceivePacketCallback callBack;

	private IoArgs ioArgs = new IoArgs();
	private ReceivePacket packetTemp;
	private byte[] buffer;
	private int total;
	private int position;

	public AsyncReceiveDispatcher(Receiver receiver, ReceivePacketCallback callBack) throws IOException {
		this.receiver = receiver;
		this.receiver.setReceiveListener(ioArgsEventListener);
		this.callBack = callBack;
	}

	@Override
	public void start() {
		registerReceive();
	}

	private void registerReceive() {
		try {
			receiver.receiveAsync(ioArgs);
		} catch (IOException e) {
			closeAndNotify();
		}
	}

	private void closeAndNotify() {
		CloseUtils.close(this);
	}

	@Override
	public void stop() {

	}

	@Override
	public void close() throws IOException {
		if(isClosed.compareAndSet(false, true)) {
			ReceivePacket packet = this.packetTemp;
			if(packet != null) {
				packetTemp = null;
				CloseUtils.close(packet);
			}
		}
	}

	private final IoArgs.IoArgsEventListener ioArgsEventListener = new IoArgs.IoArgsEventListener() {

		@Override
		public void onStarted(IoArgs args) {
			int receiveSize;
			// 刚开始的时候先接收4个字节长度
			if(packetTemp == null) {
				receiveSize = 4;
			} else {
				// 真实的内容数据
				receiveSize = Math.min(total - position, args.capacity());
			}
			// 设置本次接收数据大小
			args.limit(receiveSize);
		}

		@Override
		public void onCompleted(IoArgs args) {
			assemblePacket(args);
			// 继续接收下一条数据
			registerReceive();
		}

	};

	/**解析数据到packet
	 * @param args
	 */
	private void assemblePacket(IoArgs args) {
		if(packetTemp == null) {
			// 首先解析长度
			int length = args.readLength();
			packetTemp = new StringReceivePacket(length);
			buffer = new byte[length];
			total = length;
			position = 0;
		}

		int count = args.writeTo(buffer, 0);
		if(count > 0) {
			packetTemp.save(buffer, count);
			position += count;
			// 检查是否已完成一份packet接收
			if(position == total) {
				completePacket();
				packetTemp = null;
			}
		}
	}

	/**
	 * 完成数据接收操作
	 */
	private void completePacket() {
		ReceivePacket packet = this.packetTemp;
		CloseUtils.close(packet);
		callBack.onReceivePacketComplated(packet);
	}

}
